package top.hmtools.io;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import top.hmtools.base.StringTools;

/**
 * 文件类型判断工具类
 * @author Jianghaibo
 *
 */
public final class FileTypeTools {
    
    private FileTypeTools(){};
    
    /**
     * 当前要读取的资源文件名称
     */
    private static String contentFileName = "FileTypeDatas/FileTypeDatas.txt";

    private static final Map<String, String> FILE_TYPE_MAP;
    
    /**
     * 原始记录集合
     */
    private static List<String> contentLines;

    static {
        FILE_TYPE_MAP = new ConcurrentHashMap<String,String>();
        InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(contentFileName);
        try {
            contentLines = IoTools.readLineToStringListUTF8(inputStream);
            
            for(String line:contentLines){
                String[] item = line.split(",");
                if(item.length!=2){
                    continue;
                }
                String fileHead = item[0].trim();
                String fileType = item[1].trim();
                
                String tmp = FILE_TYPE_MAP.get(fileHead);
                if(StringTools.isBlank(tmp)){
                	FILE_TYPE_MAP.put(fileHead, fileType);
                }else{
                	FILE_TYPE_MAP.put(fileHead, tmp+";"+fileType);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 增加文件类型映射<br>
     * 如果已经存在将覆盖之前的映射
     * 
     * @param fileStreamHexHead 文件流头部Hex信息
     * @param extName 文件扩展名
     * @return 之前已经存在的文件扩展名
     */
    public static String putFileType(String fileStreamHexHead, String extName) {
        return FILE_TYPE_MAP.put(fileStreamHexHead.toUpperCase(), extName);
    }

    /**
     * 移除文件类型映射
     * 
     * @param fileStreamHexHead 文件流头部Hex信息
     * @return 移除的文件扩展名
     */
    public static String removeFileType(String fileStreamHexHead) {
        return FILE_TYPE_MAP.remove(fileStreamHexHead);
    }

    /**
     * 根据文件流的头部信息获得文件类型，及文件流头部16进制字符串
     * 
     * @param fileStreamHexHead 文件流头部16进制字符串
     * @return 文件类型，未找到为<code>null</code>
     */
    public static String getTypeAndHead(String fileStreamHexHead) {
    	if(StringTools.isBlank(fileStreamHexHead)){
    		return null;
    	}
    	fileStreamHexHead = fileStreamHexHead.trim();
    	StringBuffer result = new StringBuffer();
    	for(int ii=fileStreamHexHead.length();ii>0;ii--){
    		String key = fileStreamHexHead.substring(0, ii);
    		String resultTmp = FILE_TYPE_MAP.get(key);
    		if(StringTools.isNotBlank(resultTmp)){
    			result.append(resultTmp+"/"+key);
    			if(ii!=0){
    				result.append(";");
    			}
    		}
    	}
    	return StringTools.isBlank(result.toString().trim())?null:result.toString();
    }
    
    /**
     * 根据文件流的头部信息获得文件类型
     * @param fileStreamHexHead
     * @return
     */
    public static String getType(String fileStreamHexHead) {
    	String string = getTypeAndHead(fileStreamHexHead);
    	if(StringTools.isNotBlank(string)){
    		StringBuffer result = new StringBuffer();
    		String[] exts = string.split(";");
    		for(int ii=0;ii<exts.length;ii++){
    			String tmp = exts[ii];
    			int index = tmp.lastIndexOf("/");
    			if(index>0){
    				tmp = tmp.substring(0, index);
    			}
    			result.append(tmp+";");
    		}
    		return result.substring(0, result.length()-1).toString();
    	}else{
    		return null;
    	}
    }

    /**
     * 根据文件流的头部信息获得文件类型
     * 
     * @param in {@link InputStream}
     * @return 类型，文件的扩展名，未找到为<code>null</code>
     * @throws IOException 
     * @throws IORuntimeException 读取流引起的异常
     */
    public static String getType(InputStream in) throws IOException {
        return getType(IoTools.readToHex56Upper(in));
    }
    
    /**
     * 通过输入流获得文件类型及文件头部信息（16进制字符串）
     * @param in
     * @return
     * @throws IOException
     */
    public static String getTypeAndHead(InputStream in) throws IOException {
        return getTypeAndHead(IoTools.readToHex56Upper(in));
    }

    /**
     * 根据文件流的头部信息获得文件类型
     * @param file 文件 {@link File}
     * @return 类型，文件的扩展名，未找到为<code>null</code>
     * @throws IOException 
     * @throws FileNotFoundException 
     * @throws IORuntimeException 读取文件引起的异常
     */
    public static String getType(File file) throws FileNotFoundException, IOException  {
        return getType(new FileInputStream(file));
    }
    
    /**
     * 通过文件获得文件类型及文件头部信息（16进制字符串）
     * @param file
     * @return
     * @throws IOException
     */
    public static String getTypeAndHead(File file) throws IOException {
        return getTypeAndHead(new FileInputStream(file));
    }

    /**
     * 通过路径获得文件类型
     * 
     * @param path 路径，绝对路径或相对ClassPath的路径
     * @return 类型
     * @throws IOException 
     * @throws FileNotFoundException 
     * @throws IORuntimeException 读取文件引起的异常
     */
    public static String getTypeByPath(String path) throws FileNotFoundException, IOException {
        return getType(new File(path));
    }
    
    /**
     * 通过路径获得文件类型及文件头部信息（16进制字符串）
     * @param path
     * @return
     * @throws IOException
     */
    public static String getTypeAndHeadByPath(String path) throws IOException {
        return getTypeAndHead(new File(path));
    }
}
